﻿// Admin.NET 项目的版权、商标、专利和其他相关权利均受相应法律法规的保护。使用本项目应遵守相关法律法规和许可证的要求。
//
// 本项目主要遵循 MIT 许可证和 Apache 许可证（版本 2.0）进行分发和使用。许可证位于源代码树根目录中的 LICENSE-MIT 和 LICENSE-APACHE 文件。
//
// 不得利用本项目从事危害国家安全、扰乱社会秩序、侵犯他人合法权益等法律法规禁止的活动！任何基于本项目二次开发而产生的一切法律纠纷和责任，我们不承担任何责任！

using Admin.NET.Application.Entity;
using Admin.NET.Core.Service;
using Furion.DatabaseAccessor;
using Furion.FriendlyException;
using Mapster;
using Microsoft.AspNetCore.Http;
using SqlSugar;
using System.ComponentModel;
using System.ComponentModel.DataAnnotations;

namespace Admin.NET.Application;

/// <summary>
/// 设备管理:设备台账服务 🧩
/// </summary>
[ApiDescriptionSettings(ApplicationConst.GroupName, Order = 100)]
public class DeviceledgerService : IDynamicApiController, ITransient
{
    private readonly SqlSugarRepository<Deviceledger> _deviceledgerRep;
    private readonly ISqlSugarClient _sqlSugarClient;

    public DeviceledgerService(SqlSugarRepository<Deviceledger> deviceledgerRep, ISqlSugarClient sqlSugarClient)
    {
        _deviceledgerRep = deviceledgerRep;
        _sqlSugarClient = sqlSugarClient;
    }

    /// <summary>
    /// 分页查询设备管理:设备台账 🔖
    /// </summary>
    /// <param name="input"></param>
    /// <returns></returns>
    [DisplayName("分页查询设备管理:设备台账")]
    [ApiDescriptionSettings(Name = "Page"), HttpPost]
    public async Task<SqlSugarPagedList<DeviceledgerOutput>> Page(PageDeviceledgerInput input)
    {
        input.Keyword = input.Keyword?.Trim();
        var query = _deviceledgerRep.AsQueryable()
            .WhereIF(!string.IsNullOrWhiteSpace(input.Keyword), u => u.DeviceLedgerCode.Contains(input.Keyword) || u.DeviceLedgerName.Contains(input.Keyword))
            .WhereIF(!string.IsNullOrWhiteSpace(input.DeviceLedgerCode), u => u.DeviceLedgerCode.Contains(input.DeviceLedgerCode.Trim()))
            .WhereIF(!string.IsNullOrWhiteSpace(input.DeviceLedgerName), u => u.DeviceLedgerName.Contains(input.DeviceLedgerName.Trim()))
            .WhereIF(input.DeviceTypeId != null, u => u.DeviceTypeId == input.DeviceTypeId)
            .WhereIF(input.DeviceStateId != null, u => u.DeviceStateId == input.DeviceStateId)

            .LeftJoin<Devicetype>((u, deviceType) => u.DeviceTypeId == deviceType.Id)

            .LeftJoin<Workshop>((u, deviceType, workshop) => u.WorkshopId == workshop.Id)
            .LeftJoin<Devicestate>((u, deviceType, workshop, deviceState) => u.DeviceStateId == deviceState.Id)
            .Select((u, deviceType, workshop, deviceState) => new DeviceledgerOutput
            {
                Id = u.Id,
                DeviceLedgerCode = u.DeviceLedgerCode,
                DeviceLedgerName = u.DeviceLedgerName,
                BrandName = u.BrandName,
                DeviceTypeId = u.DeviceTypeId,
                DeviceTypeDisplayName = $"{deviceType.DeviceTypeName}",
                SpecificationModel = u.SpecificationModel,
                WorkshopId = u.WorkshopId,
                WorkshopFkDisplayName = $"{workshop.WorkshopName}",
                DeviceStateId = u.DeviceStateId,
                DeviceStateFkDisplayName = $"{deviceState.DeviceStateState}",
                DeviceLedgerPosition = u.DeviceLedgerPosition,
                Capacity = u.Capacity,
                PurchasingDate = u.PurchasingDate,
                DeviceLedgerNotes = u.DeviceLedgerNotes,
                CreateTime = u.CreateTime,
                UpdateTime = u.UpdateTime,
                CreateUserId = u.CreateUserId,
                CreateUserName = u.CreateUserName,
                UpdateUserId = u.UpdateUserId,
                UpdateUserName = u.UpdateUserName,
                IsDelete = u.IsDelete,
            });
		return await query.OrderBuilder(input).ToPagedListAsync(input.Page, input.PageSize);
    }

    /// <summary>
    /// 获取设备管理:设备台账详情 ℹ️
    /// </summary>
    /// <param name="input"></param>
    /// <returns></returns>
    [DisplayName("获取设备管理:设备台账详情")]
    [ApiDescriptionSettings(Name = "Detail"), HttpGet]
    public async Task<Deviceledger> Detail([FromQuery] QueryByIdDeviceledgerInput input)
    {
        return await _deviceledgerRep.GetFirstAsync(u => u.Id == input.Id);
    }

    /// <summary>
    /// 增加设备管理:设备台账 ➕
    /// </summary>
    /// <param name="input"></param>
    /// <returns></returns>
    [DisplayName("增加设备管理:设备台账")]
    [ApiDescriptionSettings(Name = "Add"), HttpPost]
    public async Task<long> Add(AddDeviceledgerInput input)
    {
        var entity = input.Adapt<Deviceledger>();
        return await _deviceledgerRep.InsertAsync(entity) ? entity.Id : 0;
    }

    /// <summary>
    /// 更新设备管理:设备台账 ✏️
    /// </summary>
    /// <param name="input"></param>
    /// <returns></returns>
    [DisplayName("更新设备管理:设备台账")]
    [ApiDescriptionSettings(Name = "Update"), HttpPost]
    public async Task Update(UpdateDeviceledgerInput input)
    {
        var entity = input.Adapt<Deviceledger>();
        await _deviceledgerRep.AsUpdateable(entity)
        .ExecuteCommandAsync();
    }

    /// <summary>
    /// 删除设备管理:设备台账 ❌
    /// </summary>
    /// <param name="input"></param>
    /// <returns></returns>
    [DisplayName("删除设备管理:设备台账")]
    [ApiDescriptionSettings(Name = "Delete"), HttpPost]
    public async Task Delete(DeleteDeviceledgerInput input)
    {
        var entity = await _deviceledgerRep.GetFirstAsync(u => u.Id == input.Id) ?? throw Oops.Oh(ErrorCodeEnum.D1002);
        await _deviceledgerRep.FakeDeleteAsync(entity);   //假删除
        //await _deviceledgerRep.DeleteAsync(entity);   //真删除
    }

    /// <summary>
    /// 批量删除设备管理:设备台账 ❌
    /// </summary>
    /// <param name="input"></param>
    /// <returns></returns>
    [DisplayName("批量删除设备管理:设备台账")]
    [ApiDescriptionSettings(Name = "BatchDelete"), HttpPost]
    public async Task<int> BatchDelete([Required(ErrorMessage = "主键列表不能为空")]List<DeleteDeviceledgerInput> input)
    {
        var exp = Expressionable.Create<Deviceledger>();
        foreach (var row in input) exp = exp.Or(it => it.Id == row.Id);
        var list = await _deviceledgerRep.AsQueryable().Where(exp.ToExpression()).ToListAsync();
   
        return await _deviceledgerRep.FakeDeleteAsync(list);   //假删除
        //return await _deviceledgerRep.DeleteAsync(list);   //真删除
    }
    
    /// <summary>
    /// 获取下拉列表数据 🔖
    /// </summary>
    /// <returns></returns>
    [DisplayName("获取下拉列表数据")]                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                      
    [ApiDescriptionSettings(Name = "DropdownData"), HttpPost]
    public async Task<Dictionary<string, dynamic>> DropdownData(DropdownDataDeviceledgerInput input)
    {

        var deviceTypeIdData = await _deviceledgerRep.Context.Queryable<Devicetype>()

            .Select(u => new TreeDeviceTypeOutput {
                Value = u.Id,
                Label = $"{u.DeviceTypeName}",
                Children=null
            }, true).ToTreeAsync(u => u.Children, u => u.ParentId, null);
        foreach (var item in deviceTypeIdData)
        {
            item.Children = (await GetChildren(item.Value));
        }

        var workshopIdData = await _deviceledgerRep.Context.Queryable<Workshop>()
            .InnerJoinIF<Deviceledger>(input.FromPage, (u, r) => u.Id == r.WorkshopId)
            .Select(u => new {
                Value = u.Id,
                Label = $"{u.WorkshopName}"
            }).ToListAsync();

        var deviceStateIdData = await _deviceledgerRep.Context.Queryable<Devicestate>()
            .InnerJoinIF<Deviceledger>(input.FromPage, (u, r) => u.Id == r.DeviceStateId)
            .Select(u => new {
                Value = u.Id,
                Label = $"{u.DeviceStateState}"
            }).ToListAsync();
        return new Dictionary<string, dynamic>
        {
            { "deviceTypeId", deviceTypeIdData },
            { "workshopId", workshopIdData },
            { "deviceStateId", deviceStateIdData },
        };
    }

    private async Task<List<TreeDeviceTypeOutput>> GetChildren(long? parentId)
    {
        var data = await _deviceledgerRep.Context.Queryable<Devicetype>()
            .Where(u => u.ParentId == parentId)
            .Select(u => new TreeDeviceTypeOutput
            {
                Value = u.Id,
                Label = $"{u.DeviceTypeName}"
            }).ToListAsync();
        foreach (var item in data)
        {
            item.Children = await GetChildren(item.Value);
        }
        return data;
    }



    /// <summary>
    /// 导出设备管理:设备台账记录 🔖
    /// </summary>
    /// <param name="input"></param>
    /// <returns></returns>
    [DisplayName("导出设备管理:设备台账记录")]
    [ApiDescriptionSettings(Name = "Export"), HttpPost, NonUnify]
    public async Task<IActionResult> Export(PageDeviceledgerInput input)
    {
        var list = (await Page(input)).Items?.Adapt<List<ExportDeviceledgerOutput>>() ?? new();
        if (input.SelectKeyList?.Count > 0) list = list.Where(x => input.SelectKeyList.Contains(x.Id)).ToList();
        return ExcelHelper.ExportTemplate(list, "设备管理:设备台账导出记录");
    }
    
    /// <summary>
    /// 下载设备管理:设备台账数据导入模板 ⬇️
    /// </summary>
    /// <returns></returns>
    [DisplayName("下载设备管理:设备台账数据导入模板")]
    [ApiDescriptionSettings(Name = "Import"), HttpGet, NonUnify]
    public IActionResult DownloadTemplate()
    {
        return ExcelHelper.ExportTemplate(new List<ExportDeviceledgerOutput>(), "设备管理:设备台账导入模板", (_, info) =>
        {

            if (nameof(ExportDeviceledgerOutput.DeviceTypeDisplayName) == info.Name) return _deviceledgerRep.Context.Queryable<Devicetype>().Select(u => $"{u.DeviceTypeName}").Distinct().ToList();
            if (nameof(ExportDeviceledgerOutput.WorkshopFkDisplayName) == info.Name) return _deviceledgerRep.Context.Queryable<Workshop>().Select(u => $"{u.WorkshopName}").Distinct().ToList();
            if (nameof(ExportDeviceledgerOutput.DeviceStateFkDisplayName) == info.Name) return _deviceledgerRep.Context.Queryable<Devicestate>().Select(u => $"{u.DeviceStateState}").Distinct().ToList();
            return null;
        });
    }
    
    /// <summary>
    /// 导入设备管理:设备台账记录 💾
    /// </summary>
    /// <returns></returns>
    [DisplayName("导入设备管理:设备台账记录")]
    [ApiDescriptionSettings(Name = "Import"), HttpPost, NonUnify, UnitOfWork]
    public IActionResult ImportData([Required] IFormFile file)
    {
        lock (this)
        {
            var stream = ExcelHelper.ImportData<ImportDeviceledgerInput, Deviceledger>(file, (list, markerErrorAction) =>
            {
                _sqlSugarClient.Utilities.PageEach(list, 2048, pageItems =>
                {
                    // 链接 所属分类
                    var deviceTypeIdLabelList = pageItems.Where(x => x.DeviceTypeDisplayName != null).Select(x => x.DeviceTypeDisplayName).Distinct().ToList();
                    if (deviceTypeIdLabelList.Any()) {

                        var deviceTypeIdLinkMap = _deviceledgerRep.Context.Queryable<Devicetype>().Where(u => deviceTypeIdLabelList.Contains($"{u.DeviceTypeName}")).ToList().ToDictionary(u => $"{u.DeviceTypeName}", u => u.Id);

                        pageItems.ForEach(e => {
                            e.DeviceTypeId = deviceTypeIdLinkMap.GetValueOrDefault(e.DeviceTypeDisplayName ?? "");
                            if (e.DeviceTypeId == null) e.Error = "所属分类链接失败";
                        });
                    }
                    // 链接 所属车间
                    var workshopIdLabelList = pageItems.Where(x => x.WorkshopFkDisplayName != null).Select(x => x.WorkshopFkDisplayName).Distinct().ToList();
                    if (workshopIdLabelList.Any()) {
                        var workshopIdLinkMap = _deviceledgerRep.Context.Queryable<Workshop>().Where(u => workshopIdLabelList.Contains($"{u.WorkshopName}")).ToList().ToDictionary(u => $"{u.WorkshopName}", u => u.Id);
                        pageItems.ForEach(e => {
                            e.WorkshopId = workshopIdLinkMap.GetValueOrDefault(e.WorkshopFkDisplayName ?? "");
                            if (e.WorkshopId == null) e.Error = "所属车间链接失败";
                        });
                    }
                    // 链接 设备状态
                    var deviceStateIdLabelList = pageItems.Where(x => x.DeviceStateFkDisplayName != null).Select(x => x.DeviceStateFkDisplayName).Distinct().ToList();
                    if (deviceStateIdLabelList.Any()) {
                        var deviceStateIdLinkMap = _deviceledgerRep.Context.Queryable<Devicestate>().Where(u => deviceStateIdLabelList.Contains($"{u.DeviceStateState}")).ToList().ToDictionary(u => $"{u.DeviceStateState}", u => u.Id);
                        pageItems.ForEach(e => {
                            e.DeviceStateId = deviceStateIdLinkMap.GetValueOrDefault(e.DeviceStateFkDisplayName ?? "");
                            if (e.DeviceStateId == null) e.Error = "设备状态链接失败";
                        });
                    }
                    
                    // 校验并过滤必填基本类型为null的字段
                    var rows = pageItems.Where(x => {
                        if (!string.IsNullOrWhiteSpace(x.Error)) return false;
                        if (x.WorkshopId == null){
                            x.Error = "所属车间不能为空";
                            return false;
                        }
                        if (!string.IsNullOrWhiteSpace(x.Error)) return false;
                        if (x.DeviceStateId == null){
                            x.Error = "设备状态不能为空";
                            return false;
                        }
                        return true;
                    }).Adapt<List<Deviceledger>>();
                    
                    var storageable = _deviceledgerRep.Context.Storageable(rows)
                        .SplitError(it => string.IsNullOrWhiteSpace(it.Item.DeviceLedgerCode), "设备编码不能为空")
                        .SplitError(it => it.Item.DeviceLedgerCode?.Length > 32, "设备编码长度不能超过32个字符")
                        .SplitError(it => string.IsNullOrWhiteSpace(it.Item.DeviceLedgerName), "设备名称不能为空")
                        .SplitError(it => it.Item.DeviceLedgerName?.Length > 32, "设备名称长度不能超过32个字符")
                        .SplitError(it => it.Item.BrandName?.Length > 32, "品牌名称长度不能超过32个字符")
                        .SplitError(it => it.Item.SpecificationModel?.Length > 32, "规格型号长度不能超过32个字符")
                        .SplitError(it => it.Item.WorkshopId == null, "所属车间不能为空")
                        .SplitError(it => it.Item.DeviceStateId == null, "设备状态不能为空")
                        .SplitError(it => it.Item.DeviceLedgerPosition?.Length > 32, "位置长度不能超过32个字符")
                        .SplitError(it => it.Item.Capacity?.Length > 32, "产能长度不能超过32个字符")
                        .SplitError(it => it.Item.DeviceLedgerNotes?.Length > 32, "备注长度不能超过32个字符")
                        .SplitInsert(_ => true)
                        .ToStorage();
                    
                    storageable.BulkCopy();
                    storageable.BulkUpdate();
                    
                    // 标记错误信息
                    markerErrorAction.Invoke(storageable, pageItems, rows);
                });
            });
            
            return stream;
        }
    }
}
